package com.cloud.freeflow.common.utils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mobile.device.Device;
import org.springframework.stereotype.Component;

import com.cloud.freeflow.common.context.HumanSession;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@Component
public class TokenHepler {

	@Value("${jwt.name}")
	private String APP_NAME;

	@Value("${jwt.secret}")
	public String SECRET;

	@Value("${jwt.expires_in}")
	private int EXPIRES_IN;

	@Value("${jwt.mobile_expires_in}")
	private int MOBILE_EXPIRES_IN;

	static final String AUDIENCE_UNKNOWN = "unknown";
	static final String AUDIENCE_WEB = "web";
	static final String AUDIENCE_MOBILE = "mobile";
	static final String AUDIENCE_TABLET = "tablet";

	private SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS512;

	public HumanSession parserClaims(String token) {
		HumanSession session = null;
		try {
			Claims claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody();
			session = new HumanSession();
			Integer humanId = claims.get(HumanSession.HUMAN_ID, Integer.class);
			if (null != humanId) {
				session.setHumanId(Long.valueOf(humanId));
			}
			session.setHumanName(claims.get(HumanSession.HUMAN_NAME, String.class));
			Integer unitId = claims.get(HumanSession.UNIT_ID, Integer.class);
			if (null != unitId) {
				session.setUnitId(Long.valueOf(unitId));
			}
			session.setUnitName(claims.get(HumanSession.UNIT_NAME, String.class));
			session.setUnitCode(claims.get(HumanSession.UNIT_CODE, String.class));
			String roleIds = claims.get(HumanSession.ROLE_IDS, String.class);
			if (!StringUtils.isEmpty(roleIds)) {
				List<Long> rIds = new ArrayList<Long>();
				String[] ts = roleIds.split(",");
				for (String id : ts) {
					rIds.add(Long.valueOf(id));
				}
				session.setRoleIds(rIds);
			}

		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return session;
	}

	public String generateToken(String username, Device device, Map<String, Object> claims) {
		String audience = generateAudience(device);
		return Jwts.builder().setIssuer(APP_NAME).setSubject(username).setAudience(audience).setIssuedAt(new Date())
				.setExpiration(generateExpirationDate(device)).setClaims(claims).signWith(SIGNATURE_ALGORITHM, SECRET)
				.compact();
	}

	private String generateAudience(Device device) {
		String audience = AUDIENCE_UNKNOWN;
		if (device.isNormal()) {
			audience = AUDIENCE_WEB;
		} else if (device.isTablet()) {
			audience = AUDIENCE_TABLET;
		} else if (device.isMobile()) {
			audience = AUDIENCE_MOBILE;
		}
		return audience;
	}

	private Date generateExpirationDate(Device device) {
		long expiresIn = device.isTablet() || device.isMobile() ? MOBILE_EXPIRES_IN : EXPIRES_IN;
		return new Date(new Date().getTime() + expiresIn * 1000);
	}
}
